package funtions;

import java.util.regex.Pattern;

public class FitnessFunction {

	/**
	 * This attribute must be initialize
	 */
	private String [] sentencesInformationSet;
	private String [] sentencesLengthSet;
	private int maxExecLength;
	private int maxLength;
	/**
	 * Attributes used in the method:
	 * 	public double calculateFitFunct(int[] individual)
	 */
	private int posSentence_I,posSentence_II;
	private int posInvidual;
	/**
	 * Attributes used in the method:
	 * 	private double[] sentenceTermsWeigths(String[] termsArray)
	 */
	private Pattern pTermInstanceSplit=Pattern.compile("/");
	private Pattern pTermProperties=Pattern.compile(",");
	/**
	 * Attributes used in the method:
	 * 	private String getTermStringFromPop(int sentPos_I,int sentPosII)
	 */
	private static Pattern pSentIDSplit=Pattern.compile("\t");
	/**
	 * Attributes used in the method:
	 * 	private double calculateSimilarity(int sentPos_I,int sentPos_II)
	 */
	private double[] weigths_Sent_I,weigths_Sent_II;
	private int[] termText_SentID_I,termText_SentID_II;
	private int cs_i,cs_j;
	private double numerator,denominator,sumWeg_Sen_I,sumWeg_Sen_II,similarityResult;
	/**
	 * Attributes used in the method:
	 * 	private double calculateTotalLengthInd(int [] individual)
	 */
	private int indPos;
	/**
	 * Attributes used in the method:
	 * 	public void init()
	 */
	private SentenceInfoStructure[] arrayinfoStructure;
	
	/**
	 * Requires the set of sentences in order to be able to calculate the fitness function
	 */
	public FitnessFunction(String[] sentencesInformationSet,String[] sentenceLengthS) {
		super();
		this.sentencesInformationSet = sentencesInformationSet;
		this.sentencesLengthSet=sentenceLengthS;
		this.maxLength=250;
		this.maxExecLength=this.maxLength+(this.maxLength*20/100);
	}
	/**
	 * Load all the necessary info in memory to increase performance
	 */
	public void init(){
		String sentence;
		String sentenceLength;
		String information;
		String[] termFields=new String[3];
		SentenceInfoStructure infoStructure;
		this.arrayinfoStructure=new SentenceInfoStructure[sentencesInformationSet.length];
		//Get the terms array and terms weights
		for(int w=0;w<sentencesInformationSet.length;w++){
			//File "Sent-Term_freq.txt"
			sentence=sentencesInformationSet[w];
			information=pSentIDSplit.split(sentence)[1];
			String [] termsInfo=this.pTermInstanceSplit.split(information);
			int[] terms_ids=new int[termsInfo.length];
			double[] termsWeights=new double[termsInfo.length];
			for(int k=0;k<termsInfo.length;k++){
				termFields=this.pTermProperties.split(termsInfo[k]);
				terms_ids[k]=Integer.parseInt(termFields[0]);
				termsWeights[k]=Double.parseDouble(termFields[1])*Double.parseDouble(termFields[2]);
			}
			//File "sentencesLength.txt"
			sentenceLength=this.sentencesLengthSet[w];
			int length=Integer.parseInt(this.pSentIDSplit.split(sentenceLength)[1]);
			infoStructure=new SentenceInfoStructure(terms_ids, termsWeights, length);
			this.arrayinfoStructure[w]=infoStructure;
		}
	}
	public void initCoverage(){
		SentenceInfoStructure infoStructure;
		double sentenceCoverage;
		for(int w=0;w<arrayinfoStructure.length;w++){
			infoStructure=arrayinfoStructure[w];
			sentenceCoverage=calculateCoverage(w);
			infoStructure.setCoverage(sentenceCoverage);
			arrayinfoStructure[w]=infoStructure;
		}
	}
	/**
	 * This method receives an individual whose length is |Sentences|. Is a boolean vector where 1 represents TRUE and 0 FALSE
	 * This function takes into account the restriction of maxLength. Where the max-length for execution purposes is a 20% larger
	 */
	public double calculateFitFunct(int[] individual){
		double fitnessFunctValue=0;
		double coverageValue_I=0,coverageValue_II=0;
		double redundancyValue=0;
		this.posSentence_I=0;
		this.posSentence_II=0;
		for(this.posInvidual=0;this.posInvidual<individual.length;this.posInvidual++){
			if(individual[this.posInvidual]==1&&this.posSentence_I==0){
				this.posSentence_I=this.posInvidual;
			}
			if(this.posSentence_I>0&&individual[this.posInvidual]==1&&this.posInvidual>this.posSentence_I){
				this.posSentence_II=this.posInvidual;
				//Calculate the Coverage and Redundancy function for the pair of sentences
				coverageValue_I=this.arrayinfoStructure[this.posSentence_I].getCoverage();
				coverageValue_II=this.arrayinfoStructure[this.posSentence_II].getCoverage();
				redundancyValue=calculateRedundancy(this.posSentence_I, this.posSentence_II);
				fitnessFunctValue=fitnessFunctValue+(coverageValue_I+coverageValue_II-redundancyValue);
				//
				this.posSentence_I=this.posSentence_II;
			}
		}
		//Check the individual length
		if(calculateTotalLengthInd(individual)>this.maxExecLength)
			fitnessFunctValue=0;
		return fitnessFunctValue;
	}
	/**
	 * This method receives an individual whose length is |Sentences|. Is a boolean vector where 1 represents TRUE and 0 FALSE
	 * This function *DONT* take into account the restriction of maxLength.
	 */
	public double calculateUnConstFitFunct(int[] individual){
		double fitnessFunctValue=0;
		double coverageValue_I=0,coverageValue_II=0;
		double redundancyValue=0;
		this.posSentence_I=0;
		this.posSentence_II=0;
		for(this.posInvidual=0;this.posInvidual<individual.length;this.posInvidual++){
			if(individual[this.posInvidual]==1&&this.posSentence_I==0){
				this.posSentence_I=this.posInvidual;
			}
			if(this.posSentence_I>0&&individual[this.posInvidual]==1&&this.posInvidual>this.posSentence_I){
				this.posSentence_II=this.posInvidual;
				//Calculate the Coverage and Redundancy function for the pair of sentences
				coverageValue_I=this.arrayinfoStructure[this.posSentence_I].getCoverage();
				coverageValue_II=this.arrayinfoStructure[this.posSentence_II].getCoverage();
				redundancyValue=calculateRedundancy(this.posSentence_I, this.posSentence_II);
				fitnessFunctValue=fitnessFunctValue+(coverageValue_I+coverageValue_II-redundancyValue);
				//
				this.posSentence_I=this.posSentence_II;
			}
		}
		return fitnessFunctValue;
	}
	/**
	 * Return the total length of the sentences selected in the individual.  
	 */
	public int calculateTotalLengthInd(int [] individual){
		int length=0;
		for(this.indPos=0;this.indPos<individual.length;this.indPos++){
			if(individual[this.indPos]==1){
				length=length+this.arrayinfoStructure[this.indPos].getSentenceLength();
			}
		}
		return length;
	}
	/**
	 * This function calculates the similarity between two sentences.
	 * The results of the similarity is stored in the CLASS variable:
	 * 	- similarityResult
	 * @param int sentPos_I The number id of the first sentence
	 * @param int sentPos_II The number id of the second sentence
	 */
	private void calculateSimilarity(int sentPos_I,int sentPos_II){
		this.similarityResult=0;
		this.numerator=0;
		this.denominator=0;
		//
		this.termText_SentID_I=new int[this.arrayinfoStructure[sentPos_I].getTerms_id().length];
		this.termText_SentID_I=this.arrayinfoStructure[sentPos_I].getTerms_id();
		this.weigths_Sent_I=new double[this.arrayinfoStructure[sentPos_I].getWeigths_terms().length];
		this.weigths_Sent_I=this.arrayinfoStructure[sentPos_I].getWeigths_terms();
		//_____
		this.termText_SentID_II=new int[this.arrayinfoStructure[sentPos_II].getTerms_id().length];
		this.termText_SentID_II=this.arrayinfoStructure[sentPos_II].getTerms_id();
		this.weigths_Sent_II=new double[this.arrayinfoStructure[sentPos_II].getWeigths_terms().length];
		this.weigths_Sent_II=this.arrayinfoStructure[sentPos_II].getWeigths_terms();
		//______________________________
		//Calculating the Numerator
		for(this.cs_i=0;this.cs_i<this.termText_SentID_I.length;this.cs_i++){
			for(this.cs_j=0;this.cs_j<this.termText_SentID_II.length;this.cs_j++){
				if(this.termText_SentID_I[this.cs_i]==this.termText_SentID_II[this.cs_j]){
					this.numerator=this.numerator+(this.weigths_Sent_I[this.cs_i]*this.weigths_Sent_II[this.cs_j]);
				}
			}
		}
		//Calculating the Denominator
		this.sumWeg_Sen_I=0;
		this.sumWeg_Sen_II=0;
		for(this.cs_i=0;this.cs_i<this.weigths_Sent_I.length;this.cs_i++){
			this.sumWeg_Sen_I=this.sumWeg_Sen_I+Math.pow(this.weigths_Sent_I[this.cs_i],2);
		}
		for(this.cs_j=0;this.cs_j<this.weigths_Sent_II.length;this.cs_j++){
			this.sumWeg_Sen_II=this.sumWeg_Sen_II+Math.pow(this.weigths_Sent_II[this.cs_j],2);
		}
		this.denominator=this.sumWeg_Sen_I+this.sumWeg_Sen_II;
		//_______
		this.similarityResult=this.numerator/this.denominator;
	}
	/**
	 * Calculates the coverage value for a given sentence.
	 */
	private double calculateCoverage(int sentencePosition){
		double coverageValue=0;
		for(int w=0;w<this.sentencesInformationSet.length;w++){
			calculateSimilarity(sentencePosition, w);
			coverageValue=coverageValue+this.similarityResult;
		}
		return coverageValue;
	}
	/**
	 * Calculates the redundancy value for a given pair of sentences.
	 */
	private double calculateRedundancy(int sentPos_I,int sentPos_II){
		double redundancy=0;
		calculateSimilarity(sentPos_I, sentPos_II);
		redundancy=this.similarityResult;
		return redundancy;
	}
	public int getMaxExecLength() {
		return maxExecLength;
	}
	public void setMaxExecLength(int maxExecLength) {
		this.maxExecLength = maxExecLength;
	}
	public int getMaxLength() {
		return maxLength;
	}
	public void setMaxLength(int maxLength) {
		this.maxLength = maxLength;
	}
	
	
}
